﻿Imports IICBusinessLogic

Public Class ucSystemTree

#Region "Fields"

    Private Const PERIOD_OPEN_IMAGE As Integer = 0
    Private Const PERIOD_CLOSED_IMAGE As Integer = 1

    Private Const PERIOD_CLASS_IMAGE As Integer = 2
    Private Const DIPLOMA_REQM As Integer = 5
    Private Const DIPLOMA_IMAGE As Integer = 6
    Private Const LESSON_REQM_MANDATORY_IMAGE As Integer = 8
    Private Const LESSON_REQM_OPTIONAL_IMAGE As Integer = 10
    Private Const LECTURE_IMAGE As Integer = 11

    Public Const STR_ND_DIPLOMA_ROOT As String = "ndDiplomaRoot"
    Public Const STR_ND_PERIOD_ROOT As String = "ndPeriodRoot"
    Public Const STR_ND_STUDENT_ROOT As String = "ndStudentRoot"
    Public Const STR_ND_LESSON_ROOT As String = "ndLessonRoot"
    Public Const STR_ND_CERT_ROOT As String = "ndCertRoot"
    Public Const STR_ND_MEMBER_ROOT As String = "ndMembersRoot"

    ''' <summary>
    ''' Raised when the user selects a node in the tree view where the type stored 
    ''' in the tag is PeriodClass
    ''' </summary>
    Public Event PeriodClassNodeSelected(ByVal periodClass As PeriodClass)

    Public Event LectureNodeSelected(ByVal lecture As Lecture)

    ''' <summary>
    ''' Raised when the user selects a node in the tree view where the type stored 
    ''' in the tag is Period
    ''' </summary>
    Public Event PeriodNodeSelected(ByVal period As Period)
    Public Event DiplomaSuperTypeNodeSelected(ByVal dst As DiplomaSuperType)
    Public Event DiplomaTypeNodeSelected(ByVal diplomaType As DiplomaType)
    Public Event DiplomaRequirementNodeSelected(ByVal diplomaReq As DiplomaRequirement)

    ''' <summary>
    ''' raised when the a node is selected and is not of type ClassMember,PeriodClass or Period
    ''' </summary>
    Public Event TreeChildNodeSelected(ByVal sender As Object, ByVal e As TreeViewEventArgs)

    ''' <summary>
    ''' raised when the the student root node is selected
    ''' </summary> 
    Public Event StudentRootNodeSelected()
    Public Event PeriodRootNodeSelected()
    Public Event LessonRootNodeSelected()
    Public Event DiplomaRootNodeSelected()
    Public Event MemberRootNodeSelected()

    Private diplomasLoaded As Boolean

#End Region

#Region "Tree Loading functions"

    Private Function loadCertLessonRequirementsTree(ByVal x As DiplomaRequirement) As TreeNode()

        Dim prds As List(Of CertificationRequirement) = _
                x.Certification.ActiveCertificationRequirements.ToList

        prds.Sort(New Comparison(Of CertificationRequirement)(Function(dt As CertificationRequirement, dt2 As CertificationRequirement)
                                                                  Return dt.RequiredLesson.LessonName.CompareTo(dt2.RequiredLesson.LessonName)
                                                              End Function))

        Dim lp As List(Of TreeNode) = prds.ConvertAll( _
          New Converter(Of CertificationRequirement, TreeNode) _
          (AddressOf getTreeNodeFromCertificationRequirement))

        Return lp.ToArray
    End Function

    Private Function loadPeriodNodes(ByVal x As DiplomaSuperType) As TreeNode()

        'get all periods in system under super type 'x'
        Dim prds As List(Of Period) = x.Periods.ToList
        prds.Sort()

        Dim lp As List(Of TreeNode) = prds.ConvertAll( _
          New Converter(Of Period, TreeNode)(
           AddressOf Me.getTreeNodeFromPeriod))

        Return lp.ToArray

    End Function

    Private Function loadDiplomaCertRequirementsTree(ByVal x As DiplomaType) As TreeNode()

        Dim prds As List(Of DiplomaRequirement) = x.ActiveDiplomaRequirements.ToList
        prds.Sort(New Comparison(Of DiplomaRequirement)(Function(dt As DiplomaRequirement, dt2 As DiplomaRequirement)
                                                            Return dt.Certification.CertificationType.CompareTo(dt2.Certification.CertificationType)
                                                        End Function))

        Dim lp As List(Of TreeNode) = prds.ConvertAll( _
         New Converter(Of DiplomaRequirement, TreeNode)(AddressOf getTreeNodeFromDiplomaRequirement))

        Return lp.ToArray
    End Function


    Private Sub loadDiplomaTree()

        If Me.diplomasLoaded Then Return
        Me.tvMain.Nodes(STR_ND_DIPLOMA_ROOT).Nodes.Clear()

        Dim prds As List(Of DiplomaType) = DiplomaTypeDataUtils.findList
        prds.Sort(New Comparison(Of DiplomaType)(Function(dt As DiplomaType, dt2 As DiplomaType)
                                                     Return dt.DiplomaType.CompareTo(dt2.DiplomaType)
                                                 End Function))

        Dim lp As List(Of TreeNode) = prds.ConvertAll( _
          New Converter(Of DiplomaType, TreeNode)( _
           AddressOf getTreeNodeFromDiplomaType))

        Me.tvMain.Nodes(STR_ND_DIPLOMA_ROOT).Nodes.AddRange(lp.ToArray)
        Me.diplomasLoaded = True

    End Sub

    Private Function getTreeNodeFromCertificationRequirement(ByVal pf As CertificationRequirement) As TreeNode

        Dim p As New TreeNode
        p.Name = CStr(pf.CertificationRequirementId)

        If pf.LessonIdAlternative Is Nothing Then
            p.Text = pf.RequiredLesson.LessonCode
            p.ToolTipText = pf.RequiredLesson.LessonDescription & CStr(IIf(pf.IsOptional.GetValueOrDefault, " - OPTIONAL", ""))
        Else
            p.Text = pf.RequiredLesson.LessonCode & " / " & pf.RequiredAlternativeLesson.LessonCode
            p.ToolTipText = pf.RequiredLesson.LessonDescription & vbCrLf & "OR" & vbCrLf & _
                    pf.RequiredAlternativeLesson.LessonDescription

            If pf.LessonIdAlternative1 IsNot Nothing Then
                p.Text &= " / " & pf.RequiredAlternativeLesson1.LessonCode

                p.ToolTipText &= vbCrLf & "OR" & vbCrLf & _
                    pf.RequiredAlternativeLesson.LessonDescription
            End If

        End If

        p.Tag = pf

        If pf.IsOptional Then
            p.ImageIndex = LESSON_REQM_OPTIONAL_IMAGE
        Else
            p.ImageIndex = LESSON_REQM_MANDATORY_IMAGE
        End If


        p.SelectedImageIndex = p.ImageIndex

        Return p

    End Function

    ''' <summary>
    ''' Converts a DiplomaRequirement into a tree node
    ''' </summary>
    Private Function getTreeNodeFromDiplomaRequirement(ByVal pf As DiplomaRequirement) As TreeNode

        Dim p As New TreeNode
        p.Name = CStr(pf.DiplomaRequirementId)
        p.Text = pf.Certification.CertificationType
        p.Tag = pf
        p.ToolTipText = pf.Certification.CertificationType & CStr(IIf(pf.Certification.NumberOptionalRequired.GetValueOrDefault > 0, _
                    String.Format(" - Optional Required:{0}", pf.Certification.NumberOptionalRequired.GetValueOrDefault), _
                     ""))

        p.ImageIndex = DIPLOMA_REQM
        p.SelectedImageIndex = p.ImageIndex
        p.Nodes.AddRange(loadCertLessonRequirementsTree(pf))

        Return p

    End Function

    ''' <summary>
    ''' Converts a CertificationType into a TreeNode
    ''' </summary>
    ''' <param name="pf">CertificationType model object</param>
    ''' <returns>TreeNode</returns>
    ''' <remarks></remarks>
    Private Function getTreeNodeFromCertificationType(ByVal pf As CertificationType) As TreeNode

        Dim p As New TreeNode
        p.Name = CStr(pf.CertificationTypeId)
        p.Text = pf.CertificationType
        p.Tag = pf
        p.ToolTipText = pf.CertificationType

        Return p

    End Function

    ''' <summary>
    ''' Converts a DiplomaType into a TreeNode
    ''' </summary>
    ''' <param name="pf">DiplomaType model object</param>
    ''' <returns>TreeNode</returns>
    ''' <remarks></remarks>
    Private Function getTreeNodeFromDiplomaType(ByVal pf As DiplomaType) As TreeNode
        Dim p As New TreeNode
        p.Name = CStr(pf.DiplomaTypeId)
        p.Text = pf.DiplomaType
        p.Tag = pf
        p.ToolTipText = pf.DiplomaType

        p.ImageIndex = DIPLOMA_IMAGE
        p.SelectedImageIndex = p.ImageIndex
        p.Nodes.AddRange(Me.loadDiplomaCertRequirementsTree(pf))
        Return p

    End Function


    Private Function getTreeNodeFromDiplomaSuperType(ByVal pf As DiplomaSuperType) As TreeNode

        Dim p As New TreeNode
        p.Name = CStr(pf.DiplomaSuperTypeId)
        p.Text = pf.DiplomaSuperTypeCode
        p.Tag = pf
        p.ToolTipText = pf.DiplomaSuperTypeCode
        p.Nodes.AddRange(loadPeriodNodes(pf))
        Return p

    End Function

    ''' <summary>
    ''' Converts a Period into a TreeNode
    ''' </summary>
    ''' <param name="pf">Period model object</param>
    ''' <returns>TreeNode</returns>
    ''' <remarks></remarks>
    Private Function getTreeNodeFromPeriod(ByVal pf As Period) As TreeNode

        Dim p As New TreeNode
        p.Name = CStr(pf.PeriodId)
        p.Text = pf.PeriodDescription
        p.Tag = pf
        p.ToolTipText = pf.PeriodDescription

        p.ImageIndex = CInt(IIf(pf.IsOpen.GetValueOrDefault, _
                                             PERIOD_OPEN_IMAGE, _
                                             PERIOD_CLOSED_IMAGE))
        p.SelectedImageIndex = p.ImageIndex
        p.Nodes.AddRange(loadPeriodChildNodes(pf))
        Return p

    End Function

    Private Function getTreeNodeFromPeriodClass(ByVal pf As IPeriodChild) As TreeNode

        Dim p As New TreeNode
        p.Name = pf.NodeName 'CStr(pf.ClassId)
        p.Text = pf.NodeText 'LessonDescription
        p.ToolTipText = pf.NodeTooltipText ' pf.Period.PeriodDescription & vbCrLf & pf.LessonDescription
        p.Tag = pf

        If pf.GetType Is GetType(PeriodClass) Then
            p.ImageIndex = PERIOD_CLASS_IMAGE
        Else
            p.ImageIndex = LECTURE_IMAGE
        End If

        p.SelectedImageIndex = p.ImageIndex

        Return p
    End Function

    ''' <summary>
    ''' Updates an existing Period tree node from an update of a child node
    ''' </summary>
    ''' <param name="nd">A child node</param>
    ''' <param name="period">Period object</param>
    ''' <remarks>Call this after update of any child node under a period tree node</remarks>
    Public Sub updateParentPeriodClassNode(ByVal nd As TreeNode, ByVal period As Period)

        Dim periodNode As TreeNode = nd
        Do
            If TypeOf periodNode.Tag Is Period AndAlso periodNode.Name = CStr(period.PeriodId) Then
                Exit Do
            End If
            periodNode = nd.Parent
        Loop While periodNode IsNot Nothing


        periodNode.Text = period.PeriodDescription
        periodNode.Tag = period
        periodNode.ToolTipText = period.PeriodDescription

        periodNode.ImageIndex = CInt(IIf(period.IsOpen.GetValueOrDefault, _
                                             PERIOD_OPEN_IMAGE, _
                                             PERIOD_CLOSED_IMAGE))
        periodNode.SelectedImageIndex = periodNode.ImageIndex

    End Sub


    Public Sub updatePeriodClassNode(ByVal nd As TreeNode, ByVal periodClass As PeriodClass)

        Dim periodNode As TreeNode = nd
        Do
            If TypeOf periodNode.Tag Is PeriodClass AndAlso periodNode.Name = CStr(periodClass.ClassId) Then
                Exit Do
            End If
            periodNode = nd.Parent
        Loop While periodNode IsNot Nothing


        periodNode.Text = periodClass.LessonDescription
        periodNode.Tag = periodClass
        periodNode.ToolTipText = periodClass.LessonDescription

    End Sub

    ''' <summary>
    ''' Loads periods tree.
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub loadPeriodsTree()

        '1. get all DiplomaSuperTypes
        Dim stypes As List(Of DiplomaSuperType) = DiplomaSuperTypeDataUtils.findList
        Dim stypeNodes As List(Of TreeNode) = stypes.ConvertAll( _
          New Converter(Of DiplomaSuperType, TreeNode)(
           AddressOf Me.getTreeNodeFromDiplomaSuperType))

        Dim perRootNode As TreeNode = Me.tvMain.Nodes(STR_ND_PERIOD_ROOT)
        perRootNode.Nodes.AddRange(stypeNodes.ToArray)

        'Ticket #67:"ΠΒΑΚ" tree node should not be open by default
        ''see if the period root node has child nodes and expand first node
        'If perRootNode.Nodes(0).Nodes.Count > 0 Then
        '    perRootNode.Nodes(0).Expand()
        '    perRootNode.Nodes(0).Nodes(0).Expand()
        'End If

        'perRootNode.Expand()

    End Sub


    ''' <summary>
    ''' Load classes of a period tree node
    ''' </summary>
    ''' <param name="period">Period Object</param>
    ''' <remarks></remarks>
    Private Function loadPeriodChildNodes(ByVal period As Period) As TreeNode()

        Dim periodChildNodes As List(Of IPeriodChild) = New List(Of IPeriodChild)

        period.Classes.ToList.ForEach(Sub(x)
                                          periodChildNodes.Add(x)
                                      End Sub)

        period.Lectures.ToList.ForEach(Sub(x)
                                           periodChildNodes.Add(x)
                                       End Sub)

        Dim cls As List(Of TreeNode) = periodChildNodes.ConvertAll( _
         New Converter(Of IPeriodChild, TreeNode)(
          AddressOf getTreeNodeFromPeriodClass))

        Return cls.ToArray

    End Function

    Public Sub addPeriodClass(ByVal pf As PeriodClass)

        If pf Is Nothing Then Return
        If TypeOf (Me.tvMain.SelectedNode.Tag) Is Period Then
            Dim p As TreeNode = Me.getTreeNodeFromPeriodClass(pf)
            Me.tvMain.SelectedNode.Nodes.Add(p)
            Call updateParentPeriodClassNode(p, CType(Me.tvMain.SelectedNode.Tag, Period))
        End If

    End Sub

    Public Sub addPeriodLecture(ByVal pf As Lecture)

        If pf Is Nothing Then Return

        If TypeOf (Me.tvMain.SelectedNode.Tag) Is Period Then

            Dim p As TreeNode = Me.getTreeNodeFromPeriodClass(pf)
            Me.tvMain.SelectedNode.Nodes.Add(p)
            Call updateParentPeriodClassNode(p, CType(Me.tvMain.SelectedNode.Tag, Period))
        End If

    End Sub


    Public Sub addDiplomaSuperType(ByVal pf As DiplomaSuperType)

        If pf Is Nothing Then Return
        Dim p As TreeNode = Me.getTreeNodeFromDiplomaSuperType(pf)
        Me.tvMain.Nodes(STR_ND_PERIOD_ROOT).Nodes.Insert(0, p)
        Me.tvMain.SelectedNode = p

    End Sub

    Public Sub addPeriodToTree(ByVal per As Period)

        If per Is Nothing Then Return

        Dim superTypeid As Integer = per.DiplomaSuperTypeId.GetValueOrDefault
        Dim p As TreeNode = Me.getTreeNodeFromPeriod(per)

        For Each nd As TreeNode In Me.tvMain.Nodes(STR_ND_PERIOD_ROOT).Nodes
            If IsNumeric(nd.Name) AndAlso CInt(nd.Name) = superTypeid Then
                nd.Nodes.Insert(0, p)
                'Me.tvMain.SelectedNode = p
                Return
            End If
        Next

    End Sub

    Sub addDiplomaType(ByVal diplomaType As DiplomaType)

        If diplomaType Is Nothing Then Return
        Dim lnewTreeNode As TreeNode = Me.getTreeNodeFromDiplomaType(diplomaType)
        If (lnewTreeNode Is Nothing) Then Return
        Me.tvMain.Nodes(STR_ND_DIPLOMA_ROOT).Nodes.Insert(0, lnewTreeNode)

    End Sub

    Sub addDiplomaRequierment(ByVal diplomaRequirement As DiplomaRequirement)

        If diplomaRequirement Is Nothing Then Return
        Dim lnewTreeNode As TreeNode = Me.getTreeNodeFromDiplomaRequirement(diplomaRequirement)
        If (lnewTreeNode Is Nothing) Then Return
        If TypeOf (Me.tvMain.SelectedNode.Tag) Is DiplomaType Then
            Me.tvMain.SelectedNode.Nodes.Insert(0, lnewTreeNode)
        End If

    End Sub

    Sub addCertRequirement(ByVal diplomaRequirement As CertificationRequirement)

        If diplomaRequirement Is Nothing Then Return
        Dim lnewTreeNode As TreeNode = Me.getTreeNodeFromCertificationRequirement(diplomaRequirement)
        If (lnewTreeNode Is Nothing) Then Return

        If TypeOf (Me.tvMain.SelectedNode.Tag) Is DiplomaRequirement Then
            Me.tvMain.SelectedNode.Nodes.Insert(0, lnewTreeNode)
        End If

    End Sub


#End Region

#Region "Tree View Events"

    Private Sub tvMain_AfterExpand(ByVal sender As Object, ByVal e As TreeViewEventArgs) Handles tvMain.AfterExpand

        If e.Node Is Me.tvMain.Nodes(STR_ND_DIPLOMA_ROOT) Then
            Me.loadDiplomaTree()
        End If

    End Sub

    Private Sub tvPeriods_AfterSelect(ByVal sender As Object, ByVal e As TreeViewEventArgs) _
      Handles tvMain.AfterSelect

        If e.Node Is Nothing Then Exit Sub

        If e.Action = TreeViewAction.ByKeyboard OrElse e.Action = TreeViewAction.ByMouse _
               OrElse e.Action = TreeViewAction.Unknown Then

            If e.Node Is Me.tvMain.Nodes(STR_ND_DIPLOMA_ROOT) Then
                Me.loadDiplomaTree()
                RaiseEvent DiplomaRootNodeSelected()

            ElseIf e.Node Is Me.tvMain.Nodes(STR_ND_LESSON_ROOT) Then
                RaiseEvent LessonRootNodeSelected()

            ElseIf e.Node Is Me.tvMain.Nodes(STR_ND_PERIOD_ROOT) Then
                RaiseEvent PeriodRootNodeSelected()

            ElseIf e.Node Is Me.tvMain.Nodes(STR_ND_STUDENT_ROOT) Then
                RaiseEvent StudentRootNodeSelected()

            ElseIf e.Node Is Me.tvMain.Nodes(STR_ND_MEMBER_ROOT) Then
                RaiseEvent MemberRootNodeSelected()

            Else

                If TypeOf (e.Node.Tag) Is PeriodClass Then
                    RaiseEvent PeriodClassNodeSelected(DirectCast(e.Node.Tag, PeriodClass))

                ElseIf TypeOf (e.Node.Tag) Is Lecture Then
                    RaiseEvent LectureNodeSelected(DirectCast(e.Node.Tag, Lecture))

                ElseIf TypeOf (e.Node.Tag) Is Period Then
                    RaiseEvent PeriodNodeSelected(DirectCast(e.Node.Tag, Period))

                ElseIf TypeOf (e.Node.Tag) Is DiplomaSuperType Then
                    RaiseEvent DiplomaSuperTypeNodeSelected(DirectCast(e.Node.Tag, DiplomaSuperType))
                Else
                    RaiseEvent TreeChildNodeSelected(sender, e)
                End If
            End If

        End If
    End Sub

#End Region

#Region "Context Menu arrangement"

    ''' <summary>
    ''' Shows the context menu
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub tvMain_MouseClick(ByVal sender As Object, _
                                       ByVal e As MouseEventArgs) Handles tvMain.MouseClick
        If (e.Button = MouseButtons.Right) Then

            Dim node As TreeNode = Me.tvMain.GetNodeAt(e.Location)

            If (node IsNot Nothing) Then
                Me.tvMain.SelectedNode = node
                Me.ctxTreeView.Show(Me.tvMain, e.Location)
            End If
        End If


    End Sub

    Private Sub ctxTreeView_Opening(ByVal sender As System.Object, _
      ByVal e As System.ComponentModel.CancelEventArgs) _
     Handles ctxTreeView.Opening

        If Me.tvMain.SelectedNode Is Nothing Then
            e.Cancel = True
            Return
        End If

        'let's just hide Me.tsMnAdd2 by default.
        Me.tsMnAdd2.Visible = False
        Me.tsMnAdd3.Visible = False

        'remove and add menues are visible by default, we hide then below when we do not need them
        Me.tsMnRemove.Visible = True
        Me.tsMnAdd.Visible = True

        If Me.tvMain.SelectedNode Is Me.tvMain.Nodes(STR_ND_PERIOD_ROOT) Then
            'root node!
            Me.tsMnAdd.Text = "Add Period"
            Me.tsMnRemove.Visible = False

        ElseIf Me.tvMain.SelectedNode Is Me.tvMain.Nodes(STR_ND_LESSON_ROOT) Then
            'root node!
            Me.tsMnAdd.Text = "Add Lesson"
            Me.tsMnRemove.Visible = False

        ElseIf Me.tvMain.SelectedNode Is Me.tvMain.Nodes(STR_ND_DIPLOMA_ROOT) Then
            'root node!
            Me.tsMnAdd.Text = "Add Diploma"
            Me.tsMnRemove.Visible = False

        ElseIf TypeOf (Me.tvMain.SelectedNode.Tag) Is DiplomaSuperType Then
            Me.tsMnAdd.Text = "Add Period"
            Me.tsMnRemove.Visible = False

        ElseIf TypeOf (Me.tvMain.SelectedNode.Tag) Is Period Then
            Dim p As Period = CType(Me.tvMain.SelectedNode.Tag, Period)

            'period selected.
            Me.tsMnRemove.Text = "Remove Period"
            Me.tsMnAdd.Text = "Add " & p.getClassSuffix

            If p.DiplomaSuperType.HasLectures Then
                Me.tsMnAdd2.Text = "Add Lecture"
                Me.tsMnAdd2.Visible = True
            End If

            Me.tsMnAdd3.Text = "Create New Lesson and Add as " & p.getClassSuffix
            Me.tsMnAdd3.Visible = True

        ElseIf TypeOf (Me.tvMain.SelectedNode.Tag) Is PeriodClass Then
            Dim p As Period = CType(Me.tvMain.SelectedNode.Tag, PeriodClass).Period
            Me.tsMnAdd2.Visible = True
            'period selected.
            Me.tsMnRemove.Text = "Delete " & p.getClassSuffix
            Me.tsMnAdd.Text = "Select Member/Student"
            Me.tsMnAdd2.Text = "Edit " & p.getClassSuffix

        ElseIf TypeOf (Me.tvMain.SelectedNode.Tag) Is Lecture Then
            Dim p As Period = CType(Me.tvMain.SelectedNode.Tag, Lecture).Period
            Me.tsMnAdd2.Visible = True
            'period selected.
            Me.tsMnRemove.Text = "Delete Lecture"
            Me.tsMnAdd.Text = "Select Member"
            Me.tsMnAdd2.Text = "Edit Lecture"

        ElseIf TypeOf (Me.tvMain.SelectedNode.Tag) Is DiplomaType Then
            'Diploma selected.
            Me.tsMnAdd2.Visible = True
            Me.tsMnAdd.Text = "Add Certificate Requirement"
            Me.tsMnAdd2.Text = "Create New Certificate and Add as Requirement"
            Me.tsMnRemove.Text = "Delete Diploma"

        ElseIf TypeOf (Me.tvMain.SelectedNode.Tag) Is DiplomaRequirement Then
            'Diploma required selected.
            Me.tsMnAdd2.Visible = True
            Me.tsMnAdd.Text = "Add Lesson Requirement"
            Me.tsMnAdd2.Text = "Create New Lesson and Add as Requirement"
            Me.tsMnRemove.Text = "Delete Certificate from Diploma Requirements"

        ElseIf TypeOf (Me.tvMain.SelectedNode.Tag) Is CertificationRequirement Then
            'Cert requirement selected.
            Me.tsMnAdd2.Visible = True
            Me.tsMnAdd.Text = "Add Lesson as Requirement"
            Me.tsMnAdd2.Text = "Create New Lesson and Add as Requirement"
            Me.tsMnRemove.Text = "Delete Lesson from Cert Requirements"

        End If

        Dim isPeriodSelected As Boolean = TypeOf (Me.tvMain.SelectedNode.Tag) Is Period
        Me.mnOpenPeriod.Visible = isPeriodSelected
        Me.mnClosePeriod.Visible = isPeriodSelected
        Me.mnProcessPeriod.Visible = isPeriodSelected
        Me.mnReverseProcessPeriod.Visible = isPeriodSelected
        Me.mnSepPeriod.Visible = isPeriodSelected

        'OpenPeriod is available only for closed periods, ie if isOpen = false
        Me.mnOpenPeriod.Enabled = isPeriodSelected AndAlso _
           CType(Me.tvMain.SelectedNode.Tag, Period).IsOpen.GetValueOrDefault = False

        'ClosePeriod is available only for open periods, ie if isOpen = true
        Me.mnClosePeriod.Enabled = isPeriodSelected AndAlso _
           CType(Me.tvMain.SelectedNode.Tag, Period).IsOpen.GetValueOrDefault = True

        'ProcessPeriod is available only for open periods, ie if close menu is enabled
        Me.mnProcessPeriod.Enabled = Me.mnClosePeriod.Enabled
        Me.mnReverseProcessPeriod.Enabled = Me.mnClosePeriod.Enabled AndAlso _
           CType(Me.tvMain.SelectedNode.Tag, Period).isProcessed = True

    End Sub

#End Region

#Region "Period Operations"


    Private Sub mnOpenPeriod_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
     Handles mnOpenPeriod.Click, mnClosePeriod.Click, mnProcessPeriod.Click, mnReverseProcessPeriod.Click

        If Me.tvMain.SelectedNode Is Nothing OrElse _
          TypeOf (Me.tvMain.SelectedNode.Tag) Is Period = False Then
            Call winUtils.MsgboxStop("Please select a period from the tree view.")
            Return
        End If

        If sender Is mnOpenPeriod Then
            Call OpenPeriod(CType(Me.tvMain.SelectedNode.Tag, Period))

        ElseIf sender Is mnClosePeriod Then
            Call ClosePeriod(CType(Me.tvMain.SelectedNode.Tag, Period))

        ElseIf sender Is mnProcessPeriod Then
            Call ProcessPeriod(CType(Me.tvMain.SelectedNode.Tag, Period))

        ElseIf sender Is mnReverseProcessPeriod Then
            Dim pp As New UIReversePeriod()
            pp.processReversePeriod(CType(Me.tvMain.SelectedNode.Tag, Period))

        End If

    End Sub

    Private Sub OpenPeriod(ByVal period As Period)

        'ask user to confirm
        If winUtils.MsgboxQuestion( _
         "Are you sure you want to Open period " & period.PeriodDescription & "?") _
           <> MsgBoxResult.Yes Then Exit Sub

        period.openPeriod()
        PeriodDataUtils.savePeriod(period)
        Me.refreshPeriod(period)

    End Sub

    Private Sub ClosePeriod(ByVal period As Period)

        'ask user to confirm
        If winUtils.MsgboxQuestion( _
         "Are you sure you want to Close period " & period.PeriodDescription & "?") _
           <> MsgBoxResult.Yes Then Exit Sub

        period.closePeriod()
        PeriodDataUtils.savePeriod(period)
        Me.refreshPeriod(period)

    End Sub

    Private Sub ProcessPeriod(ByVal period As Period)

        Dim pp As New UIProcessPeriod()
        pp.processPeriod(period)



    End Sub

#End Region

    Private Sub frmPeriodTree_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
      Handles Me.Load

        If Me.DesignMode Then Exit Sub
        Me.loadPeriodsTree()

    End Sub


    ''' <summary>
    ''' Refreshes a period on the tree after it has been updated by frmPeriodDetails
    ''' </summary>
    ''' <param name="pf">Period Object</param>
    ''' <remarks></remarks>
    Public Sub refreshPeriod(ByVal pf As Period)

        Dim perRootNode As TreeNode = Me.tvMain.Nodes(STR_ND_PERIOD_ROOT)
        'note: .Find() searched for the node name
        Dim tnodes As TreeNode() = perRootNode.Nodes.Find(CStr(pf.PeriodId), True)

        If tnodes IsNot Nothing Then

            Array.ForEach(tnodes, Sub(x)
                                      x.Name = CStr(pf.PeriodId)
                                      x.Text = pf.PeriodDescription
                                      x.Tag = pf
                                      x.ImageIndex = CInt(IIf(pf.IsOpen.GetValueOrDefault, _
                                                      PERIOD_OPEN_IMAGE, _
                                                      PERIOD_CLOSED_IMAGE))
                                      x.SelectedImageIndex = x.ImageIndex

                                  End Sub)


        End If

    End Sub


End Class
